package com.lookme.lmtool.utils;

import com.lookme.lmtool.model.Rect;

import javax.imageio.ImageIO;
import javax.xml.bind.DatatypeConverter;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.List;

/**
 * 图像相关操作类
 */
public class ImageUtils {
    private static int THRESHOLD=300;
    public static boolean isBlack(int colorInt) {
        Color color = new Color(colorInt);
        if (color.getRed() + color.getGreen() + color.getBlue() <= THRESHOLD) {
            return true;
        }
        return false;
    }

    public static boolean isWhite(int colorInt) {
        Color color = new Color(colorInt);
        if (color.getRed() + color.getGreen() + color.getBlue() > THRESHOLD) {
            return true;
        }
        return false;
    }

    public static BufferedImage drawGrid(BufferedImage previewImage,Color color, float gap) {
        int width = previewImage.getWidth();
        int height = previewImage.getHeight();

        int rows=(int)(height/gap);
        int cols=(int)(width/gap);

        Graphics2D g=previewImage.createGraphics();
        g.setColor(color);
        // draw the rows
        int rowHt = height / (rows);
        for (int i = 0; i < rows; i++) {
            g.drawLine(0, i * rowHt, width, i * rowHt);
        }

        // draw the columns
        int rowWid = width / (cols);
        for (int i = 0; i < cols; i++) {
            g.drawLine(i * rowWid, 0, i * rowWid, height);
        }
        return previewImage;
    }

    public static BufferedImage removeVerticalBlank(BufferedImage img) throws Exception {
        int width = img.getWidth();
        int height = img.getHeight();
        int start = 0;
        int end = 0;
        Label1: for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                if (ImageUtils.isBlack(img.getRGB(x, y))) {
                    start = y;
                    break Label1;
                }
            }
        }
        Label2: for (int y = height - 1; y >= 0; --y) {
            for (int x = 0; x < width; ++x) {
                if (ImageUtils.isBlack(img.getRGB(x, y))) {
                    end = y;
                    break Label2;
                }
            }
        }
        return img.getSubimage(0, start, width, end - start + 1);
    }
    public static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight){
        Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_AREA_AVERAGING);
        BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
        return outputImage;
    }
    public static BufferedImage removeHorizontalBlank(BufferedImage img) throws Exception {
        int width = img.getWidth();
        int height = img.getHeight();
        int start = 0;
        int end = 0;
        Label1: for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if (ImageUtils.isBlack(img.getRGB(x, y))) {
                    start = x;
                    break Label1;
                }
            }
        }
        Label2: for (int x = width-1; x >=0;x--) {
            for (int y = 0; y < height; y++) {
                if (ImageUtils.isBlack(img.getRGB(x, y))) {
                    end = x;
                    break Label2;
                }
            }
        }
        return img.getSubimage(start, 0, end - start + 1, height);
    }

    /**
     * Base64转换为图片服务
     * targetPath  输出视频文件路径,不需要文件名
     * */
    public static BufferedImage base64ToImg(String base64){
        if (base64 == null || "".equals(base64)){
            return null;
        }
        File file = null;
        FileOutputStream fops = null;
        base64 = base64.replace("data:image/jpeg;base64,","");
        base64 = base64.replace("data:image/png;base64,","");
        base64 = base64.replace("data:image/gif;base64,","");
        byte[] buff = DatatypeConverter.parseBase64Binary(base64);
        try {
            BufferedImage img= ImageIO.read(new ByteArrayInputStream(buff));
            return img;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static BufferedImage copyImage(BufferedImage source){
        int type=source.getType();
        if(type==0){
            type=BufferedImage.TYPE_3BYTE_BGR;
        }
        BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), type);
        Graphics g = b.getGraphics();
        g.drawImage(source, 0, 0, null);
        g.dispose();
        return b;
    }


    public static int fxColorToInt(javafx.scene.paint.Color c) {
        return fxColorToAwtColor(c).getRGB();
    }

    public static java.awt.Color fxColorToAwtColor(javafx.scene.paint.Color c) {
        int r =(int)(c.getRed()*255);
        int g =(int)(c.getGreen()*255);
        int b =(int)(c.getBlue()*255);
        int a =(int)c.getOpacity();
        int opacity = a * 255 ;
        java.awt.Color awtColor = new java.awt.Color(r, g, b, opacity);
        return awtColor;
    }

    public static javafx.scene.paint.Color awtColorToFxColor(java.awt.Color c) {
        int r = c.getRed();
        int g = c.getGreen();
        int b = c.getBlue();
        int a = c.getAlpha();
        double opacity = a / 255.0 ;
        javafx.scene.paint.Color fxColor = javafx.scene.paint.Color.rgb(r, g, b, opacity);
        return fxColor;
    }

    public static javafx.scene.paint.Color intToFxColor(int color) {
        float r = ((color >> 16) & 0xff) / 255.0f;
        float g = ((color >>  8) & 0xff) / 255.0f;
        float b = ((color      ) & 0xff) / 255.0f;
        float a = ((color >> 24) & 0xff) / 255.0f;
        return new javafx.scene.paint.Color(r, g, b, a);
    }
    public static java.awt.Color intToAwtColor(int color) {
        int r = ((color >> 16) & 0xff);
        int g = ((color >>  8) & 0xff);
        int b = ((color      ) & 0xff);
        int a = ((color >> 24) & 0xff);
        return new java.awt.Color(r, g, b, a);
    }

    public static String awtColorToHexValue(java.awt.Color  color) {
        return intToHexValue((int)color.getAlpha()) + intToHexValue((int)color.getRed()) + intToHexValue((int)color.getGreen()) + intToHexValue((int)color.getBlue());
    }

    private static String intToHexValue(int number) {
        String result = Integer.toHexString(number & 0xff);
        while (result.length() < 2) {
            result = "0" + result;
        }
        return result.toUpperCase();
    }

    public static Map<Integer,Integer> getRangeColor(BufferedImage bi, int px, int py, int w, int h){
        Map<Integer,Integer> cs=new HashMap<Integer,Integer>();
//        for (int y = py; y <py+h; y+=(py+h)/5) {
//            for (int x = px; x < py+w; x++) {
//                int color=bi.getRGB(x,y);
//                int value=1;
//                Color cc = new Color(bi.getRGB(x, y));
//                if(color==Color.white.getRGB()||(cc.getRed()>250&&cc.getGreen()>250&&cc.getBlue()>250)){
//                    continue;
//                }
//                if(cs.containsKey(color)){
//                    value=cs.get(color);
//                    value++;
//                }else{
//                }
//                cs.put(color,value);
//            }
//        }

        for(int x=px;x<px+w;x++){
            for(int y=py;y<py+h;y++){
                int color=bi.getRGB(x,y);
                int value=1;
                Color cc = new Color(bi.getRGB(x, y));
                if(color==Color.white.getRGB()||(cc.getRed()>253&&cc.getGreen()>253&&cc.getBlue()>253)){
                    continue;
                }
                if(cs.containsKey(color)){
                    value=cs.get(color);
                    value++;
                }else{
                }
                cs.put(color,value);
            }
        }
        cs=sortMapByValue(cs);
        return cs;
    }

    public static Map<Integer,Integer> getRangeOutColor(BufferedImage bi,int px,int py,int w,int h){
        int width=bi.getWidth();
        int height=bi.getHeight();
        Map<Integer,Integer> cs=new HashMap<Integer,Integer>();
        for (int y = 0; y <py; y++) {
            for (int x = 0; x < py; x++) {
                int color=bi.getRGB(x,y);
                int value=1;
                Color cc=new Color(color);
                if(color==Color.white.getRGB()||(cc.getRed()>250&&cc.getGreen()>250&&cc.getBlue()>250)){
                    continue;
                }
                if(cs.containsKey(color)){
                    value=cs.get(color);
                    value++;
                }else{
                }
                cs.put(color,value);
            }
        }

        for (int y = py+h; y <height-1; y++) {
            for (int x = px+w; x < width-1; x++) {
                int color=bi.getRGB(x,y);
                int value=1;
                if(cs.containsKey(color)){
                    value=cs.get(color);
                    value++;
                }
                cs.put(color,value);
            }
        }
        cs=sortMapByValue(cs);
        return cs;
    }

    public static Map<Integer,Integer> sortMapByValue(Map<Integer,Integer> oriMap) {
        if (oriMap == null || oriMap.isEmpty()) {
            return null;
        }
        Map<Integer,Integer> sortedMap = new LinkedHashMap<Integer,Integer>();
        List<Map.Entry<Integer,Integer>> entryList = new ArrayList<Map.Entry<Integer,Integer>>(
                oriMap.entrySet());
        Collections.sort(entryList, new ImageUtils.MapValueComparator());
        Iterator<Map.Entry<Integer,Integer>> iter = entryList.iterator();
        Map.Entry<Integer,Integer> tmpEntry = null;
        while (iter.hasNext()) {
            tmpEntry = iter.next();
            sortedMap.put(tmpEntry.getKey(), tmpEntry.getValue());
        }
        return sortedMap;
    }




    public static Rect getRemoveBlankRect(BufferedImage src, Rect rect) {
        int width = rect.getX()+rect.getWidth();
        int height = rect.getY()+rect.getHeight();
        int startY = 0;
        int endY = height;
        Label1: for (int y = rect.getY(); y < height; ++y) {
            for (int x = rect.getX(); x < width; ++x) {
                if (ImageUtils.isBlack(src.getRGB(x, y))) {
                    startY = y;
                    break Label1;
                }
            }
        }
        Label2: for (int y = height - 1; y >= rect.getY(); --y) {
            for (int x = rect.getX(); x < width; ++x) {
                if (ImageUtils.isBlack(src.getRGB(x, y))) {
                    endY = y;
                    break Label2;
                }
            }
        }

        int startX = 0;
        int endX = width;
        Label3: for (int x = rect.getX(); x < width; x++) {
            for (int y = rect.getY(); y < height; y++) {
                if (ImageUtils.isBlack(src.getRGB(x, y))) {
                    startX = x;
                    break Label3;
                }
            }
        }
        Label4: for (int x = width-1; x >=rect.getX();x--) {
            for (int y = rect.getY(); y < height; y++) {
                if (ImageUtils.isBlack(src.getRGB(x, y))) {
                    endX = x;
                    break Label4;
                }
            }
        }

        return new Rect(startX,startY,endX-startX+1,endY-startY+1,null);
    }

    public static int getRectPoint(BufferedImage src, Rect rect) {
        int width = rect.getX()+rect.getWidth();
        int height = rect.getY()+rect.getHeight();
        int point=0;
        for (int x = rect.getX(); x < width; x++) {
            for (int y = rect.getY(); y < height; y++) {
                if (ImageUtils.isBlack(src.getRGB(x, y))) {
                    point+=1;
                }
            }
        }

        return point;
    }

    static class MapValueComparator implements Comparator<Map.Entry<Integer,Integer>> {
        @Override
        public int compare(Map.Entry<Integer,Integer> me1, Map.Entry<Integer,Integer> me2) {
            return me2.getValue().compareTo(me1.getValue());
        }
    }
}
